package com.ly.mp.busicen.rule.field;

import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StringUtils;

import com.ly.mp.busicen.common.context.BusicenException;
import com.ly.mp.busicen.rule.field.article.IFieldArticle;
import com.ly.mp.busicen.rule.field.article.IFieldArticleContainer;
import com.ly.mp.busicen.rule.field.execution.IValidExecution;
import com.ly.mp.busicen.rule.field.execution.ValidFieldData;
import com.ly.mp.busicen.rule.field.execution.ValidResultCtn;
import com.ly.mp.busicen.rule.field.validator.Validation;
import com.ly.mp.busicen.rule.flow.FlowUserMode;

public class FireFieldRule implements IFireFieldRule {
	
	Logger log = LoggerFactory.getLogger(FireFieldRule.class);

	@Autowired
	IFieldArticleContainer fieldArticleContainer; // 字段校验的
	
	@Autowired
	IValidExecution validExcution; // 错误信息构建

	/**
	 * 
	 * @Description: 执行字段校验
	 * @param entity 需要校验的实体
	 * @param article BUSINESSFLOW_SENCECODE 字段
	 * @param type DATA_TYPE 字段
	 */
	@Override
	public ValidResultCtn fireRule(Object entity, String article,String type) {
		return fireRule(entity, article, type, null);
	}
	
	/**
	 * 
	 * @MethodName: ruleToValidation
	 * @Description: TODO
	 * @param entity 转换成map的实体
	 * @param articles 数据库配置的校验规则
	 * @return List<ValidFieldData>
	 */
	public List<ValidFieldData> ruleToValidation(Map<String, ?> entity,List<IFieldArticle> articles){
		List<ValidFieldData> result = new ArrayList<ValidFieldData>();
		articles.forEach(r->{
			ValidFieldData validFieldData = new ValidFieldData();
			validFieldData.setField(r.field());
			validFieldData.setFiledName(r.fieldName());
			validFieldData.setValue(entity.get(r.field()));
			validFieldData.setSource(entity);
			validFieldData.setValidations(new ArrayList<Validation>());
			// 把t_prc_db_sence_validatecolum 中的VALIDATE_CONTENT使用 ; 分隔
			String[] statements = splitStatements(r.statement());
			Optional.ofNullable(statements).ifPresent(m->{
				for (String statement : m) {
					validFieldData.getValidations().add(Validation.build(statement));
				}
			});			
			result.add(validFieldData);
		});		
		return result;
	}
	
	public String[] splitStatements(String statements){
		if (StringUtils.isEmpty(statements)) {
			return null;
		}
		return statements.split(";");
	}

	@SuppressWarnings("unchecked")
	public Map<String,?> convertToMap(Object entity) {
		if (entity == null) {
			throw new NullPointerException("传入校验对象为空");
		}
		if (entity instanceof Map) {
			return (Map<String,?>) entity;
		}
		return entityToMap(entity);

	}

	public Map<String, Object> entityToMap(Object entity) {
		if (entity == null) {
			return null;
		}
		Map<String, Object> result = new HashMap<String, Object>();
		try {
			BeanInfo beanInfo = Introspector.getBeanInfo(entity.getClass());
			PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
			for (PropertyDescriptor m : propertyDescriptors) {
				String name = m.getName();
				if (name.equals("callback")||name.equals("callbacks")||name.equals("class")) {
					continue;
				}
				Method method = m.getReadMethod();
				result.put(name, method.invoke(entity));
			}
		} catch (Exception e) {
			log.error("字段校验数据转换异常",e);
			throw new RuntimeException(e);
		}
		return result;
	}

	@Override
	public void fireRuleExcpt(Object entity, String article, String type) {
		fireRuleExcpt(entity, article, type, null);	
	}

	@Override
	public ValidResultCtn fireRule(Object entity, String article, String type, String brand) {	
		List<IFieldArticle> articles = fieldArticleContainer.getArticles(article+type,FlowUserMode.currentContext(brand));
		Map<String, ?> target = convertToMap(entity);
		List<ValidFieldData> validations = ruleToValidation(target, articles);
		ValidResultCtn validResultCtn = new ValidResultCtn();
		validations.forEach(m->{
			validResultCtn.getResults().add(validExcution.validField(m));
		});
		return validResultCtn;
	}

	@Override
	public void fireRuleExcpt(Object entity, String article, String type, String brand) {
		ValidResultCtn result = fireRule(entity, article, type,brand);
		if (!result.isValid()) {
			throw BusicenException.create(result.getNotValidMessage());
		}
	}

}
